/**    
 * 文件名：DoAutoPayService.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2017年12月1日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.models.prepayment.service;

import java.util.Date;

import com.logic.common.domain.Code;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.enums.BillStatusEnum;
import com.logic.landseaserver.common.util.DateUtil;
import com.logic.landseaserver.domain.BalanceSheetRecord;
import com.logic.landseaserver.models.independent.service.BillIndependentService;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.ws.dto.ContractDTO;
import com.logic.system.persistence.read.CodeReadMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.logic.landseaserver.common.LandeaConstants.BillType;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.PaymentResultCode;
import com.logic.landseaserver.common.util.Arith;
import com.logic.landseaserver.common.util.LandSeaUtil;
import com.logic.landseaserver.common.util.StringTools;
import com.logic.landseaserver.domain.AccountBalance;
import com.logic.landseaserver.domain.AccountChargeback;
import com.logic.landseaserver.domain.BillPayment;
import com.logic.landseaserver.models.payment.PaymentConstant;
import com.logic.landseaserver.models.payment.PaymentConstant.BillPaymentStatus;
import com.logic.landseaserver.models.payment.PaymentConstant.BillTypeCode;
import com.logic.landseaserver.models.payment.PaymentConstant.PayType;
import com.logic.landseaserver.models.payment.service.AbstractPaymentResponseHandler;
import com.logic.landseaserver.models.prepayment.bean.AccountBalanceResp;
import com.logic.landseaserver.models.prepayment.bean.AotuPayBill;
import com.logic.landseaserver.persistence.write.AccountBalanceWriteMapper;
import com.logic.landseaserver.persistence.write.AccountChargebackWriteMapper;
import com.logic.landseaserver.persistence.write.BillPaymentWriteMapper;
import com.logic.system.AppContext;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：DoAutoPayService</br>
 * 类描述：开始抵扣</br>
 * 创建人：Aaron</br>
 * 创建时间：2017年12月1日 下午5:55:14</br>
 * @version 1.0
 *
 */
@Service
public class DoAutoPayService
{
    /*
     * 由于Spring的@Transactional的限制，在需要事务的地方只能由bean调用，因此抽出方法
     * 方法必须为public
     */
    
    protected static final Logger LOGGER = LoggerFactory.getLogger(DoAutoPayService.class);
    
    // 实时
    public static final String REALBILL = "REAL";
    
    // 首期或月结
    public static final String FIRSTORMONTH = "FIRSTORMONTH";
    
    @Autowired
    private AccountBalanceWriteMapper accountBalanceWriteMapper;
    
    @Autowired
    private AccountChargebackWriteMapper accountChargebackWriteMapper;
    
    @Autowired
    private BillPaymentWriteMapper billPaymentWriteMapper;

    @Autowired
    private BillIndependentService billIndependentService;

    @Autowired
    private ContractReadMapper contractReadMapper;

    @Autowired
    private CodeReadMapper codeReadMapper;
    
    @Autowired
    private AppContext appContext;
    
    /**
     * 
     * [简要描述]：余额自动抵扣</br>
     * [详细描述]：每次抵扣独立不影响其他抵扣，异常要内部消化</br>
     * [作者]：Aaron(2017-11-30)</br>
     * 
     * @throws LandseaException
     *
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = {LandseaException.class, Exception.class})
    public void doAutoPay(AccountBalanceResp autoPayCommonBalance, AotuPayBill aotuPayBill)
        throws LandseaException
    {
        if (null == autoPayCommonBalance)
        {
            return;
        }
        
        LOGGER.info("autoPay|" + autoPayCommonBalance.getBalanceType() + "余额开始抵扣" + aotuPayBill.getBillTypeZh()
            + ",AccountId=" + autoPayCommonBalance.getAccountId());
        
        String accountIdStr = String.valueOf(autoPayCommonBalance.getAccountId());
        
        // 余额
        double balanceMoney = LandSeaUtil.get2Double(autoPayCommonBalance.getMoney());
        
        // 账单还需支付金额
        double billMoney = Arith.sub(aotuPayBill.getMoney(), aotuPayBill.getPaidDetailMoney());
        // 记录下原始的已支付金额
        aotuPayBill.setSourcePaidDetailMoney(aotuPayBill.getPaidDetailMoney());
        
        // 日志记录账单金额
        double logBillMoney = billMoney;
        // 最终抵扣的金额
        double aotuPayMoney = 0.00d;
        
        // 注：实时金额要一次性抵扣完毕
        String paymentBillType = getPaymentBillType(aotuPayBill.getProcessType(), aotuPayBill.getBillDateDesc());
        if (balanceMoney <= 0 || (BillType.REALTIME_BILL.equals(paymentBillType) && billMoney > balanceMoney))
        {
            // 余额不足，直接退出 或者实时账单只能一次性抵扣完毕
            LOGGER.info("autoPay|余额为" + balanceMoney + "金额不足，无法抵扣" + aotuPayBill.getBillTypeZh() + "，结束.");
            return;
        }
        
        if (billMoney <= 0)
        {
            LOGGER.info("autoPay|" + aotuPayBill.getBillTypeZh() + "还需支付金额为0，无需余额抵扣，结束.");
            return;
        }
        
        if (billMoney <= balanceMoney)
        {
            aotuPayMoney = billMoney;
            balanceMoney = Arith.sub(balanceMoney, billMoney);
        }
        else
        {
            aotuPayMoney = balanceMoney;
            balanceMoney = 0.00d;
        }
        
        // 更新已收
        aotuPayBill.setPaidMoney(Arith.add(aotuPayBill.getPaidMoney(), aotuPayMoney));
        // 更新详情已支付的钱
        aotuPayBill.setPaidDetailMoney(Arith.add(aotuPayBill.getPaidDetailMoney(), aotuPayMoney));
        
        // 抵扣时间
        Date autoPayDate = new Date();
        
        // 生成支付记录
        BillPayment insertBillPayment = new BillPayment();
        insertBillPayment.setMoney(aotuPayMoney);
        insertBillPayment.setBillId(aotuPayBill.getBillId());
        insertBillPayment.setBillType(paymentBillType);
        insertBillPayment.setPayType(PayType.BALANCE_AUTOPAY);
        insertBillPayment.setTime(autoPayDate);
        // 直接就是支付成功的
        insertBillPayment.setStatus(BillPaymentStatus.SUCCESS);
        insertBillPayment.setComments(autoPayCommonBalance.getBalanceType() + "余额抵扣"
                + aotuPayBill.getBillTypeZh()+"|"+aotuPayBill.getBillDateDesc()+aotuPayBill.getBillMonth());
        insertBillPayment.updateCommonInfo(-1);
        billPaymentWriteMapper.insertSelective(insertBillPayment);
        LOGGER.info("autoPay|accountId=" + accountIdStr + "|生成payment支付记录paymentId=" + insertBillPayment.getId());
        
        // 更新余额表,如果有冻结金额，更新冻结金额
        double frozenMoney = LandSeaUtil.get2Double(autoPayCommonBalance.getFreezeMoney());
        AccountBalance accountBalanceUpdate = new AccountBalance();
        accountBalanceUpdate.setId(autoPayCommonBalance.getAccountBalanceId());
        accountBalanceUpdate.setMoney(balanceMoney);
        autoPayCommonBalance.setMoney(balanceMoney);
        if (frozenMoney > 0)
        {
            frozenMoney = frozenMoney >= aotuPayMoney ? Arith.sub(frozenMoney, aotuPayMoney) : 0.00d;
            autoPayCommonBalance.setFreezeMoney(frozenMoney);
            accountBalanceUpdate.setFreezeMoney(frozenMoney);
        }
        accountBalanceWriteMapper.updateByPrimaryKeySelective(accountBalanceUpdate);
        LOGGER.info("autoPay|accountId=" + accountIdStr + "|更新余额,更新冻结金额为" + frozenMoney);
        
        // 生成余额支付记录
        String remark = null == aotuPayBill.getBillNo() ? aotuPayBill.getBillMonth() : aotuPayBill.getBillNo();
        String acbakComment = aotuPayBill.getBillDateDesc() + "|" + remark;
        AccountChargeback accountChargeback = new AccountChargeback();
        accountChargeback.setAccountId(autoPayCommonBalance.getAccountId());
        accountChargeback.setBalanceType(autoPayCommonBalance.getBalanceTypeCode());
        accountChargeback.setFeeType(aotuPayBill.getBillType());
        accountChargeback.setMoney(aotuPayMoney);
        accountChargeback.setRemark(acbakComment);
        accountChargeback.setTime(autoPayDate);
        accountChargeback.setLeftMoney(balanceMoney);
        accountChargeback.setWid(StringTools.generateUuid());
        accountChargeback.initCommonField();
        accountChargebackWriteMapper.insertSelective(accountChargeback);
        LOGGER.info("autoPay|accountId=" + accountIdStr + "|生成余额扣款记录Id=" + accountChargeback.getId());

        //独立账单入记录 抵扣成功，往独立账单添加一条负值的记录
        ContractDTO contractDTO = contractReadMapper.queryContractDetail(aotuPayBill.getContractId());
        if(contractDTO!=null){
            Date nowD  = new Date();
            BalanceSheetRecord bsr = new BalanceSheetRecord();
            bsr.setContractNo(contractDTO.getContractNo());
            bsr.setProjectId(contractDTO.getProjectId());
            bsr.setRoomId(contractDTO.getRoomId());
            bsr.setHouseNum(contractDTO.getRoomNo());
            bsr.setContractId(contractDTO.getId());
            bsr.setBillId(autoPayCommonBalance.getAccountId());
           // bsr.setBillNo(aotuPayBill.getBillNo());
            bsr.setBillMonth(aotuPayBill.getBillMonth());
            bsr.setBillType(LandeaConstants.BillType.RECHARGE_PAY);
            bsr.setAmountReceived(-aotuPayMoney);
            bsr.setReceivableMoney(-aotuPayMoney);
            bsr.setBillStatus(BillStatusEnum.BIST2.getCode());
            bsr.setPayTime(new Date());
            bsr.setExpenditureCode(autoPayCommonBalance.getBalanceTypeCode());
            bsr.setExpenditure(StringTools.getEmunName(autoPayCommonBalance.getBalanceTypeCode()));
            bsr.setStartTime(nowD);
            bsr.setEndTime(nowD);
            bsr.setProduceType(LandeaConstants.ProduceType.AUTOPAY);
            Code code = codeReadMapper.selectByPrimaryKey(aotuPayBill.getBillType());
            if(code !=null){
                bsr.setMark("账户余额转 "+code.getCodeDescZh());
            }else{
                bsr.setMark("账户余额转？");
            }
            billIndependentService.insertBalanceSheet(bsr);
            LOGGER.info("自动抵扣时添加独立账单完毕.");
        }
        // 抵扣后账单处理
        String processBeanId = paymentBillType + PaymentConstant.PAYMENT_RESPONSE_SUFFIX;
        
        // 根据账单类型路由处理组件，路由不到报错
        Object handerObject = appContext.getBean(processBeanId);
        if (null == handerObject)
        {
            LOGGER.error("autoPay|没找到账单处理路由processBeanId="+ processBeanId +",accountId=" + accountIdStr);
            throw LandseaException.createException(PaymentResultCode.E00150032);
        }
        
        AbstractPaymentResponseHandler paymentRequestHandler = (AbstractPaymentResponseHandler)handerObject;
        paymentRequestHandler.aotoPayDoLocalBusiness(aotuPayBill, insertBillPayment);
        
        StringBuilder sbBuilder = new StringBuilder();
        sbBuilder.append("autoPay|");
        sbBuilder.append(aotuPayBill.getBillTypeZh());
        sbBuilder.append("还需支付");
        sbBuilder.append(logBillMoney);
        sbBuilder.append("元,"+ autoPayCommonBalance.getBalanceType() +"余额自动抵扣");
        sbBuilder.append(aotuPayMoney);
        sbBuilder.append("元,抵扣后余额剩余");
        sbBuilder.append(balanceMoney);
        sbBuilder.append("元");
        LOGGER.info(sbBuilder.toString());
    }
    
    /**
     * 
     * [简要描述]：获取支付记录表中的billType</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-01)</br>
     *
     * @param processType
     * @param billName
     * @return
     *
     */
    private String getPaymentBillType(String processType, String billName)
    {
        if (REALBILL.equals(processType))
        {
            return BillTypeCode.REAL_TIME;
        }
        
        if (billName.startsWith("首期"))
        {
            return BillTypeCode.FIRST_PAY;
        }
        
        return BillTypeCode.MONTH_PAY;
    }
}
